#include "scaler.h"

#include <stdio.h>
#include "crane_lcdc.h"
#include "../camera/cam_offline.h"
#include "../common/media_clock.h"
#include "../../lvgl/src/lv_misc/lv_debug.h"
#include "lvgl/src/lv_misc/lv_color.h"
#include "lvgl/src/lv_draw/lv_draw_img.h"

#if USE_CRANE_CAMERA && defined USE_LCD_PLATFORM_ROTATION_DEGREE
static uint8_t *rotation_buf = NULL;
extern unsigned is_phase1;
extern int cam_offline_rotation(struct cam_offline_buf* buf_src, struct cam_offline_buf* buf_dst, enum offline_rot rot, int module_id);
#endif

extern void invalidate_dcache_range(unsigned long start, unsigned long stop);

static inline uint8_t saturate_u8(int32_t a)
{
    return (a > (int32_t)UINT8_MAX) ? UINT8_MAX : ((a < 0) ? 0 : a);
}

static const int16_t CRV[256] = {
    -176,-175,-173,-172,-170,-169,-168,-166,-165,-164,-162,-161,
    -159,-158,-157,-155,-154,-153,-151,-150,-149,-147,-146,-144,
    -143,-142,-140,-139,-138,-136,-135,-133,-132,-131,-129,-128,
    -127,-125,-124,-122,-121,-120,-118,-117,-116,-114,-113,-112,
    -110,-109,-107,-106,-105,-103,-102,-101, -99, -98, -96, -95,
     -94, -92, -91, -90, -88, -87, -85, -84, -83, -81, -80, -79,
     -77, -76, -75, -73, -72, -70, -69, -68, -66, -65, -64, -62,
     -61, -59, -58, -57, -55, -54, -53, -51, -50, -48, -47, -46,
     -44, -43, -42, -40, -39, -38, -36, -35, -33, -32, -31, -29,
     -28, -27, -25, -24, -22, -21, -20, -18, -17, -16, -14, -13,
     -11, -10,  -9,  -7,  -6,  -5,  -3,  -2,   0,   1,   2,   4,
       5,   6,   8,   9,  10,  12,  13,  15,  16,  17,  19,  20,
      21,  23,  24,  26,  27,  28,  30,  31,  32,  34,  35,  37,
      38,  39,  41,  42,  43,  45,  46,  47,  49,  50,  52,  53,
      54,  56,  57,  58,  60,  61,  63,  64,  65,  67,  68,  69,
      71,  72,  74,  75,  76,  78,  79,  80,  82,  83,  84,  86,
      87,  89,  90,  91,  93,  94,  95,  97,  98, 100, 101, 102,
     104, 105, 106, 108, 109, 111, 112, 113, 115, 116, 117, 119,
     120, 121, 123, 124, 126, 127, 128, 130, 131, 132, 134, 135,
     137, 138, 139, 141, 142, 143, 145, 146, 148, 149, 150, 152,
     153, 154, 156, 157, 158, 160, 161, 163, 164, 165, 167, 168,
     169, 171, 172, 174};

static const int16_t CGU[256] = {
      43,  42,  42,  42,  41,  41,  41,  40,  40,  40,  39,  39,
      39,  38,  38,  38,  37,  37,  37,  36,  36,  36,  35,  35,
      35,  34,  34,  34,  33,  33,  33,  32,  32,  32,  31,  31,
      31,  30,  30,  30,  29,  29,  29,  28,  28,  28,  27,  27,
      27,  26,  26,  25,  25,  25,  24,  24,  24,  23,  23,  23,
      22,  22,  22,  21,  21,  21,  20,  20,  20,  19,  19,  19,
      18,  18,  18,  17,  17,  17,  16,  16,  16,  15,  15,  15,
      14,  14,  14,  13,  13,  13,  12,  12,  12,  11,  11,  11,
      10,  10,  10,   9,   9,   9,   8,   8,   8,   7,   7,   7,
       6,   6,   6,   5,   5,   5,   4,   4,   4,   3,   3,   3,
       2,   2,   2,   1,   1,   1,   0,   0,   0,  -1,  -1,  -2,
      -2,  -2,  -3,  -3,  -3,  -4,  -4,  -4,  -5,  -5,  -5,  -6,
      -6,  -6,  -7,  -7,  -7,  -8,  -8,  -8,  -9,  -9,  -9, -10,
     -10, -10, -11, -11, -11, -12, -12, -12, -13, -13, -13, -14,
     -14, -14, -15, -15, -15, -16, -16, -16, -17, -17, -17, -18,
     -18, -18, -19, -19, -19, -20, -20, -20, -21, -21, -21, -22,
     -22, -22, -23, -23, -23, -24, -24, -24, -25, -25, -25, -26,
     -26, -26, -27, -27, -28, -28, -28, -29, -29, -29, -30, -30,
     -30, -31, -31, -31, -32, -32, -32, -33, -33, -33, -34, -34,
     -34, -35, -35, -35, -36, -36, -36, -37, -37, -37, -38, -38,
     -38, -39, -39, -39, -40, -40, -40, -41, -41, -41, -42, -42,
     -42, -43, -43, -43};

static const int16_t CGV[256] = {
      89,  88,  87,  87,  86,  85,  85,  84,  83,  83,  82,  81,
      80,  80,  79,  78,  78,  77,  76,  76,  75,  74,  73,  73,
      72,  71,  71,  70,  69,  69,  68,  67,  67,  66,  65,  64,
      64,  63,  62,  62,  61,  60,  60,  59,  58,  57,  57,  56,
      55,  55,  54,  53,  53,  52,  51,  50,  50,  49,  48,  48,
      47,  46,  46,  45,  44,  43,  43,  42,  41,  41,  40,  39,
      39,  38,  37,  36,  36,  35,  34,  34,  33,  32,  32,  31,
      30,  30,  29,  28,  27,  27,  26,  25,  25,  24,  23,  23,
      22,  21,  20,  20,  19,  18,  18,  17,  16,  16,  15,  14,
      13,  13,  12,  11,  11,  10,   9,   9,   8,   7,   6,   6,
       5,   4,   4,   3,   2,   2,   1,   0,   0,  -1,  -2,  -3,
      -3,  -4,  -5,  -5,  -6,  -7,  -7,  -8,  -9, -10, -10, -11,
     -12, -12, -13, -14, -14, -15, -16, -17, -17, -18, -19, -19,
     -20, -21, -21, -22, -23, -24, -24, -25, -26, -26, -27, -28,
     -28, -29, -30, -31, -31, -32, -33, -33, -34, -35, -35, -36,
     -37, -37, -38, -39, -40, -40, -41, -42, -42, -43, -44, -44,
     -45, -46, -47, -47, -48, -49, -49, -50, -51, -51, -52, -53,
     -54, -54, -55, -56, -56, -57, -58, -58, -59, -60, -61, -61,
     -62, -63, -63, -64, -65, -65, -66, -67, -68, -68, -69, -70,
     -70, -71, -72, -72, -73, -74, -74, -75, -76, -77, -77, -78,
     -79, -79, -80, -81, -81, -82, -83, -84, -84, -85, -86, -86,
     -87, -88, -88, -89};

static const int16_t CBU[256] = {
    -222,-221,-219,-217,-215,-214,-212,-210,-208,-207,-205,-203,
    -201,-200,-198,-196,-195,-193,-191,-189,-188,-186,-184,-182,
    -181,-179,-177,-175,-174,-172,-170,-169,-167,-165,-163,-162,
    -160,-158,-156,-155,-153,-151,-149,-148,-146,-144,-143,-141,
    -139,-137,-136,-134,-132,-130,-129,-127,-125,-124,-122,-120,
    -118,-117,-115,-113,-111,-110,-108,-106,-104,-103,-101, -99,
     -98, -96, -94, -92, -91, -89, -87, -85, -84, -82, -80, -78,
     -77, -75, -73, -72, -70, -68, -66, -65, -63, -61, -59, -58,
     -56, -54, -52, -51, -49, -47, -46, -44, -42, -40, -39, -37,
     -35, -33, -32, -30, -28, -26, -25, -23, -21, -20, -18, -16,
     -14, -13, -11,  -9,  -7,  -6,  -4,  -2,   0,   1,   3,   5,
       6,   8,  10,  12,  13,  15,  17,  19,  20,  22,  24,  25,
      27,  29,  31,  32,  34,  36,  38,  39,  41,  43,  45,  46,
      48,  50,  51,  53,  55,  57,  58,  60,  62,  64,  65,  67,
      69,  71,  72,  74,  76,  77,  79,  81,  83,  84,  86,  88,
      90,  91,  93,  95,  97,  98, 100, 102, 103, 105, 107, 109,
     110, 112, 114, 116, 117, 119, 121, 123, 124, 126, 128, 129,
     131, 133, 135, 136, 138, 140, 142, 143, 145, 147, 148, 150,
     152, 154, 155, 157, 159, 161, 162, 164, 166, 168, 169, 171,
     173, 174, 176, 178, 180, 181, 183, 185, 187, 188, 190, 192,
     194, 195, 197, 199, 200, 202, 204, 206, 207, 209, 211, 213,
     214, 216, 218, 220};

static inline void yuv2rgb565(uint8_t *rgb, uint8_t y,
                  int ruv, int guv, int buv)
{
    uint16_t *rgb565 = (uint16_t *)rgb;
    int r = saturate_u8(y + ruv) >> 3;
    int g = saturate_u8(y + guv) >> 2;
    int b = saturate_u8(y + buv) >> 3;
    lv_color_t px_color;

    px_color.ch.red = (uint16_t)r;
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 1
    px_color.ch.green_h = (uint16_t)(g >> 3);
    px_color.ch.green_l = (uint16_t)(g & 0x7U);
#else
    px_color.ch.green = (uint16_t)g;
#endif
    px_color.ch.blue = (uint16_t)b;

    *rgb565 = px_color.full;
}

#if USE_CRANE_CAMERA
#ifndef USE_WATCH_LITE
static unsigned offline_rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
    struct cam_offline_buf src;
    struct cam_offline_buf dst;
    memset(&src, 0, sizeof(struct cam_offline_buf));
    memset(&dst, 0, sizeof(struct cam_offline_buf));
    src.width = src_width;
    src.height = src_height;
    src.pixelformat = SCALER_INPUT_FMT_RGB565;
    src.stride = src_width*2;
    src.plane_addr[0] = (unsigned int)src_buf;

    dst.width = dst_width;
    dst.height = dst_height;
    dst.pixelformat = SCALER_INPUT_FMT_RGB565;
    dst.stride = dst_width*2;
    dst.plane_addr[0] = (unsigned int)dst_buf;

    flush_cache((unsigned long)src_buf, (unsigned long)src_width*src_height*2);

    invalidate_dcache_range((unsigned long)dst_buf,
                       (unsigned long)dst_buf + dst_width*dst_height*2);
    if(common_offline_scaler(&src, &dst, MODULE_DISPLAY) < 0) {
        printf("Fail: rgb565, scaler error!\n");
        return 0;
    }
    return 1;
}

static unsigned offline_rgb888_2_rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
    //uart_printf("offline_rgb888_2_rgb565_scale: (%d, %d) -> (%d, %d)\n", src_width, src_height, dst_width, dst_height);
    struct cam_offline_buf src;
    struct cam_offline_buf dst;
    uint8_t *tmp_buf = lv_mem_aligned_alloc(dst_width*dst_height*3, 32);
    if(tmp_buf == NULL) {
        printf("Fail: rgb888 to 565, no memory!\n");
        return 0;
    }
    flush_cache((unsigned long)src_buf, (unsigned long)src_width * src_height * 3);

    invalidate_dcache_range((unsigned long)tmp_buf,
                       (unsigned long)tmp_buf + dst_width*dst_height*3);

    memset(&src, 0, sizeof(struct cam_offline_buf));
    memset(&dst, 0, sizeof(struct cam_offline_buf));
    src.width = src_width;
    src.height = src_height;
    src.pixelformat = SCALER_INPUT_FMT_RGB888;
    src.stride = src_width*3;
    src.plane_addr[0] = (unsigned int)src_buf;

    dst.width = dst_width;
    dst.height = dst_height;
    dst.pixelformat = SCALER_INPUT_FMT_RGB888;
    dst.stride = dst_width*3;
    dst.plane_addr[0] = (unsigned int)tmp_buf;

    if(common_offline_scaler(&src, &dst, MODULE_DISPLAY) < 0) {
        printf("Fail: rgb888 to 565, scaler error!\n");
        lv_mem_aligned_free(tmp_buf);
        return 0;
    }

    lv_color_rgb888_to_16((lv_color_rgb888_t *)tmp_buf,
        (lv_color16_t *)dst_buf,
        dst_width * dst_height);
    lv_mem_aligned_free(tmp_buf);

    return 1;
}

static unsigned offline_rgba8888_2_rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
    //uart_printf("lcdc_rgba_2_rgb565_scale: (%d, %d) -> (%d, %d)\n", src_width, src_height, dst_width, dst_height);
    struct cam_offline_buf src;
    struct cam_offline_buf dst;
    uint8_t *tmp_buf = lv_mem_aligned_alloc(dst_width*dst_height*4, 32);
    if(tmp_buf == NULL) {
        printf("Fail: rgba to 565, no memory!\n");
        return 0;
    }
    flush_cache((unsigned long)src_buf, (unsigned long)src_width * src_height * 4);

    invalidate_dcache_range((unsigned long)tmp_buf,
                       (unsigned long)tmp_buf + dst_width*dst_height*4);

    memset(&src, 0, sizeof(struct cam_offline_buf));
    memset(&dst, 0, sizeof(struct cam_offline_buf));
    src.width = src_width;
    src.height = src_height;
    src.pixelformat = SCALER_INPUT_FMT_ARGB32;
    src.stride = src_width*4;
    src.plane_addr[0] = (unsigned int)src_buf;

    dst.width = dst_width;
    dst.height = dst_height;
    dst.pixelformat = SCALER_INPUT_FMT_ARGB32;
    dst.stride = dst_width*4;
    dst.plane_addr[0] = (unsigned int)tmp_buf;

    if(common_offline_scaler(&src, &dst, MODULE_DISPLAY) < 0) {
        printf("Fail: rgba to 565, scaler error!\n");
        lv_mem_aligned_free(tmp_buf);
        return 0;
    }

    lv_color_rgba8888_to_16_alpha((lv_color_rgba8888_t *)tmp_buf,
        (lv_color16_alpha_t *)dst_buf,
        dst_width * dst_height);
    lv_mem_aligned_free(tmp_buf);
    return 1;
}
#endif
static unsigned offline_yuv420_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf,
                   uint8_t semi)
{
    struct cam_offline_buf srcBuf = {0}, dstBuf = {0};

    srcBuf.width = src_width;
    srcBuf.height = src_height;
    srcBuf.stride = src_width;
    dstBuf.width = dst_width;
    dstBuf.height = dst_height;
    dstBuf.stride = dst_width;
    if(semi) {  /* input image is YUV420SP */
        srcBuf.plane_addr[0] = (unsigned int)src_buf;
        srcBuf.plane_addr[1] = (unsigned int)(src_buf + src_width*src_height);
        srcBuf.pixelformat = SCALER_INPUT_FMT_YUV420_NV12;
        dstBuf.plane_addr[0] = (unsigned int)dst_buf;
        dstBuf.plane_addr[1] = (unsigned int)(dst_buf + dst_width*dst_height);
        dstBuf.pixelformat = SCALER_INPUT_FMT_YUV420_NV12;
    } else {  /* input image is YUV420P */
        srcBuf.plane_addr[0] = (unsigned int)src_buf;
        srcBuf.plane_addr[1] = (unsigned int)(src_buf + src_width*src_height);
        srcBuf.plane_addr[2] = (unsigned int)(src_buf + src_width*src_height +
                                           src_width*src_height/4);
        srcBuf.pixelformat = SCALER_INPUT_FMT_YUV420_I420;
        dstBuf.plane_addr[0] = (unsigned int)dst_buf;
        dstBuf.plane_addr[1] = (unsigned int)(dst_buf + dst_width*dst_height);
        dstBuf.plane_addr[2] = (unsigned int)(dst_buf + dst_width*dst_height +
                                           dst_width*dst_height/4);
        dstBuf.pixelformat = SCALER_INPUT_FMT_YUV420_I420;
    }

    int size = src_width*src_height;
    size += size/2;
    flush_cache((unsigned long)src_buf, size);
    invalidate_dcache_range((unsigned long)dst_buf, (unsigned long)(dst_buf+dst_width*dst_height*3/2));

    int ret = common_offline_scaler(&srcBuf, &dstBuf, 0);
    if(ret != 0 ) {
        printf("scale image error=%d\n", ret);
        return 0;
    }
    return 1;
}

#endif

#define RED_BITS(x)  lv_color_get_red_bits(x)
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 1
#define GREEN_H_BITS(x)  lv_color_get_green_h_bits(x)
#define GREEN_L_BITS(x)  lv_color_get_green_l_bits(x)
#else
#define GREEN_BITS(x)  lv_color_get_green_bits(x)
#endif
#define BLUE_BITS(x)  lv_color_get_blue_bits(x)

__attribute__ ((unused)) static unsigned sw_rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
    double wscale = (double)src_width / dst_width;
    double hscale = (double)src_height / dst_height;

    uint16_t *src_data = (uint16_t *)src_buf;
    uint16_t *dst_data = (uint16_t *)dst_buf;
    int dy = 0, dx = 0;
    double sy = 0, sx = 0;
    double weighty = 0.0, weightx= 0.0;
    int y1 = 0, y2 = 0, x1 = 0, x2 = 0;
    for(dy = 0; dy < dst_height; dy++){
        sy = (double)dy * hscale;
        y1 = (int)sy;
        y2 = y1 + 1;
        weighty = sy - y1;

        dx = 0;
        for(dx = 0; dx < dst_width; dx++){
            sx = (double)dx * wscale;
            x1 = (int)sx;
            x2 = x1 + 1;
            weightx = sx - x1;

            double tlx_r = (1.0 - weightx) * RED_BITS(src_data[x1 + y1 * src_width]);
            double trx_r = weightx * RED_BITS(src_data[x2 + y1 * src_width]);
            double blx_r = (1.0 - weightx) * RED_BITS(src_data[x1 + y2 * src_width]);
            double brx_r = weightx * RED_BITS(src_data[x2 + y2 * src_width]);
            double ty_r = (1.0 - weighty) * (tlx_r + trx_r);
            double by_r = weighty * (blx_r + brx_r);

#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 1
            double tlx_g_h = (1.0 - weightx) * GREEN_H_BITS(src_data[x1 + y1 * src_width]);
            double trx_g_h = weightx * GREEN_H_BITS(src_data[x2 + y1 * src_width]);
            double blx_g_h = (1.0 - weightx) * GREEN_H_BITS(src_data[x1 + y2 * src_width]);
            double brx_g_h = weightx * GREEN_H_BITS(src_data[x2 + y2 * src_width]);
            double ty_g_h = (1.0 - weighty) * (tlx_g_h + trx_g_h);
            double by_g_h = weighty * (blx_g_h + brx_g_h);

            double tlx_g_l = (1.0 - weightx) * GREEN_L_BITS(src_data[x1 + y1 * src_width]);
            double trx_g_l = weightx * GREEN_L_BITS(src_data[x2 + y1 * src_width]);
            double blx_g_l = (1.0 - weightx) * GREEN_L_BITS(src_data[x1 + y2 * src_width]);
            double brx_g_l = weightx * GREEN_L_BITS(src_data[x2 + y2 * src_width]);
            double ty_g_l = (1.0 - weighty) * (tlx_g_l + trx_g_l);
            double by_g_l = weighty * (blx_g_l + brx_g_l);
#else
            double tlx_g = (1.0 - weightx) * GREEN_BITS(src_data[x1 + y1 * src_width]);
            double trx_g = weightx * GREEN_BITS(src_data[x2 + y1 * src_width]);
            double blx_g = (1.0 - weightx) * GREEN_BITS(src_data[x1 + y2 * src_width]);
            double brx_g = weightx * GREEN_BITS(src_data[x2 + y2 * src_width]);
            double ty_g = (1.0 - weighty) * (tlx_g + trx_g);
            double by_g = weighty * (blx_g + brx_g);
#endif

            double tlx_b = (1.0 - weightx) * BLUE_BITS(src_data[x1 + y1 * src_width]);
            double trx_b = weightx * BLUE_BITS(src_data[x2 + y1 * src_width]);
            double blx_b = (1.0 - weightx) * BLUE_BITS(src_data[x1 + y2 * src_width]);
            double brx_b = weightx * BLUE_BITS(src_data[x2 + y2 * src_width]);
            double ty_b = (1.0 - weighty) * (tlx_b + trx_b);
            double by_b = weighty * (blx_b + brx_b);

#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 1
            lv_color_t px_color;
            px_color.ch.red = ((uint16_t)(ty_r + by_r));
            px_color.ch.green_h = ((uint16_t)(ty_g_h + by_g_h));
            px_color.ch.green_l = ((uint16_t)(ty_g_l + by_g_l));
            px_color.ch.blue = (uint16_t)(ty_b + by_b);
#else
            //dst_data[dx + dy * dst_width]= ((uint16_t)(ty_r + by_r)<<11) + ((uint16_t)(ty_g + by_g)<<5) + (uint16_t)(ty_b + by_b);
            lv_color_t px_color;
            px_color.ch.red = ((uint16_t)(ty_r + by_r));
            px_color.ch.green = ((uint16_t)(ty_g + by_g));
            px_color.ch.blue = (uint16_t)(ty_b + by_b);
#endif

            dst_data[dx + dy * dst_width]= px_color.full;
        }
    }
    return 1;
}

__attribute__ ((unused)) static void sw_yuv420_2_rgb565(int width, int height, const unsigned char *src, unsigned short *dst, unsigned semi)
{
    int line, col;
    int y, u, v, ruv, guv, buv;
    const unsigned char *py, *pu, *pv;
    uint8_t *pd = (uint8_t *)dst;

    py = src;
    pu = py + (width * height);
    if(semi) { //nv12
        pv = pu + 1;
    } else {   //I420
        pv = pu + (width * height)/4;
    }

    for (line = 0; line < height; line+=2) {
        for (col = 0; col < width; col+=2) {
            y = *py;
            u = *pu;
            v = *pv;

            ruv = CRV[v];
            guv = CGV[v] + CGU[u];
            buv = CBU[u];

            yuv2rgb565(pd, y, ruv, guv, buv);
            y = *(py+1);
            yuv2rgb565(pd + 2, y, ruv, guv, buv);
            y = *(py+width);
            yuv2rgb565(pd + 2*width, y, ruv, guv, buv);
            y = *(py+width+1);
            yuv2rgb565(pd + 2*width + 2, y, ruv, guv, buv);

            pd += 4;
            py += 2;

            if(semi) {
                pu += 2;
                pv += 2;
            } else {
                pu += 1;
                pv += 1;
            }
        }
        py += width;
        pd += (width*2);
    }
}

void yuv420_2_rgb565(int width, int height, const unsigned char *src, unsigned short *dst, unsigned semi)
{
    return sw_yuv420_2_rgb565(width, height, src, dst, semi);
}

unsigned rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
#if USE_CRANE_CAMERA  && (!defined(USE_WATCH_LITE))
    return offline_rgb565_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf);
#elif USE_CRANE_LCD
    return lcdc_rgb565_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf);
#else
    lv_img_sw_565_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf, false);
    return 1;
#endif
}

unsigned rgb888_2_rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
#if USE_CRANE_CAMERA && (!defined(USE_WATCH_LITE))
    return offline_rgb888_2_rgb565_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf);
#elif USE_CRANE_LCD
    return lcdc_rgb888_2_rgb565_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf);
#else
    lv_color16_t * img_buf_565 = (lv_color16_t *)lv_mem_aligned_alloc(src_width * src_height * sizeof(lv_color16_t), 32);
    lv_color_rgb888_to_16((lv_color_rgb888_t *)src_buf, img_buf_565, src_width * src_height);
    lv_img_sw_565_scale(src_width, src_height, dst_width, dst_height, (uint8_t *)img_buf_565, dst_buf, false);
    lv_mem_aligned_free(img_buf_565);
    return 1;
#endif
}

unsigned rgba8888_2_rgb565_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf)
{
#if USE_CRANE_CAMERA  && (!defined(USE_WATCH_LITE))
    return offline_rgba8888_2_rgb565_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf);
#else
    lv_color16_alpha_t * img_buf_565 = (lv_color16_alpha_t *)lv_mem_aligned_alloc(src_width * src_height * sizeof(lv_color16_alpha_t), 32);
    lv_color_rgba8888_to_16_alpha((lv_color_rgba8888_t *)src_buf, img_buf_565, src_width * src_height);
    lv_img_sw_565_scale(src_width, src_height, dst_width, dst_height, (uint8_t *)img_buf_565, dst_buf, true);
    lv_mem_aligned_free(img_buf_565);
    return 1;
#endif
}

unsigned yuv420_scale(int32_t src_width,
                   int32_t src_height,
                   int32_t dst_width,
                   int32_t dst_height,
                   uint8_t *src_buf,
                   uint8_t *dst_buf,
                   uint8_t semi)
{
#if USE_CRANE_CAMERA
    return offline_yuv420_scale(src_width, src_height, dst_width, dst_height, src_buf, dst_buf, semi);
#else
    return 1;
#endif
}

#if USE_CRANE_CAMERA && defined USE_LCD_PLATFORM_ROTATION_DEGREE
static unsigned get_rotation_degree(int degree)
{
    if(degree == 90) {
        return ROT_90_DEG;
    } else if(degree == 180) {
        return ROT_180_DEG;
    } else if(degree == 270) {
        return ROT_270_DEG;
    } else {
        printf("lcd rotation degree error: %d !!!\n", degree);
        return 0;
    }
}

lv_color_t* hw_fb_rotation(lv_area_t * area, lv_color_t *fb, int degree)
{
    int32_t x1 = (*area).x1;
    int32_t y1 = (*area).y1;
    int32_t x2 = (*area).x2;
    int32_t y2 = (*area).y2;
    int32_t width, height, stride;

    if (degree == 0) {
        return fb;
    }

    if (is_phase1 != 0)
    {
        printf("hw_rotaton can not be used before phase2!!!");
        ASSERT(0);
    }

    width = x2 - x1 + 1;
    height = y2 - y1 + 1;
    stride = width * 2;  // for color16
    if(rotation_buf == NULL) {
        rotation_buf = lv_mem_aligned_alloc(width * height * 2, 32);
        if(rotation_buf == NULL) {
            LV_LOG_ERROR("Error: rotation flush no memory!! \n");
            return fb;
        }
    }

    struct cam_offline_buf src_buf;
    struct cam_offline_buf dst_buf;
    src_buf.width = width;
    src_buf.height = height;
    src_buf.stride = stride;
    src_buf.pixelformat = SCALER_INPUT_FMT_RGB565;
    src_buf.plane_addr[0] = (unsigned int)fb;
    if ((degree == 90) || (degree == 270)) {
        dst_buf.width = height;
        dst_buf.height = width;
        stride = height*2;
        dst_buf.stride = stride;
        width = dst_buf.width;
        height = dst_buf.height;
    } else {
        dst_buf.width = width;
        dst_buf.height = height;
        dst_buf.stride = stride;
    }
    dst_buf.pixelformat = SCALER_INPUT_FMT_RGB565;
    dst_buf.plane_addr[0] = (unsigned int)rotation_buf;

    flush_cache((unsigned long)fb, stride*height);
    invalidate_dcache_range((unsigned long)dst_buf.plane_addr[0] ,
           (unsigned long)dst_buf.plane_addr[0] + (dst_buf.stride)*(dst_buf.height));
    cam_offline_rotation(&src_buf, &dst_buf, (enum offline_rot)get_rotation_degree(degree), 0);

    if (degree == 270) {
        (*area).x1 = y1;
        (*area).y1 = LV_HOR_RES - x1 - height;
    } else if (degree == 180) {
        (*area).x1 = LV_HOR_RES - x1 - width;
        (*area).y1 = LV_VER_RES - y1 - height;
    } else {
        (*area).y1 = x1;
        (*area).x1 = LV_VER_RES - y1 - width;
    }
    (*area).x2 = (*area).x1 + width - 1;
    (*area).y2 = (*area).y1 + height - 1;
    return (lv_color_t *)rotation_buf;
}
#endif

lv_color_t* fb_rotation(lv_area_t * area, lv_color_t *fb, int degree)
{
#if USE_CRANE_CAMERA && defined USE_LCD_PLATFORM_ROTATION_DEGREE
    return hw_fb_rotation(area, fb, degree);
#else
    if (degree != 0) {
        printf("err: rotation not supported\n");
    }
    return fb;
#endif
}
